﻿using System;
using System.Net;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Documents;
using System.Windows.Ink;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Animation;
using System.Windows.Shapes;
using System.Reflection;
using System.Collections.Generic;

namespace RStein.PosterousReader.Common.ViewModelsHelpers
{
  public class PersistentStateHelper : IPersistentStateHelper
  {

    public virtual Dictionary<string, object> GetPersistentData(Object obj)
    {
      checkObjNotNull(obj);
      List<PropertyInfo> properties = getPersistentProperties(obj);

      if (!properties.Any())
      {
        return null;
      }

      Dictionary<string, Object> propertyValues = getPropertyValues(obj, properties);
      if (!propertyValues.Any())
      {
        return null;
      }

      return propertyValues;
    }



    public virtual void SetPersistentData(object obj, Dictionary<string, object> state)
    {
      checkObjNotNull(obj);
      if (state == null)
      {
        return;
      }

      var propertyValues = state as Dictionary<string, Object>;
      if (propertyValues == null)
      {
        return;
      }

      restorePropertyValues(obj, state);
    }

    private void restorePropertyValues(object obj, Dictionary<string, object> state)
    {
     var properties = getPersistentProperties(obj);
     properties.ToList()
               .ForEach(property =>
               {
                 object propertyValue;

                 if (state.TryGetValue(property.Name, out propertyValue))
                 {
                   property.SetValue(obj, propertyValue, null);
                 }
               });

    }

    private List<PropertyInfo> getPersistentProperties(Object obj)
    {
      var properties = obj.GetType()
                          .GetProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.Static | BindingFlags.FlattenHierarchy)
                          .Where(property => property.GetCustomAttributes(typeof(PersistentStateAttribute), false).Any() &&
                                                 property.GetIndexParameters().Count() == 0 &&
                                                 property.CanWrite &&
                                                 property.GetSetMethod() != null).ToList();
      return properties;

    }

    private Dictionary<string, Object> getPropertyValues(Object obj, List<PropertyInfo> properties)
    {
      var propertyValues = new Dictionary<string, object>
                           (
                             (from property in properties
                              select new
                              {
                                Key = property.Name,
                                Value = property.GetValue(obj, null)

                              }).Where(pair => pair.Value != null)
                               .ToDictionary(pair => pair.Key, pair => pair.Value)
                           );


      return propertyValues;
    }
    
    private void checkObjNotNull(object obj)
    {
      if (obj == null)
      {
        throw new ArgumentNullException("obj");
      }
    }


  }
}
